//
// Created by wxd on 2025/7/15.
//

#include "ResourceLoadUtils.h"

#include <stdexcept>

#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"

std::unique_ptr<ResourceLoadUtils> ResourceLoadUtils::instance = nullptr;
std::once_flag ResourceLoadUtils::m_InitFlag;
std::unordered_map<const char*, ImageParam> ResourceLoadUtils::m_LoadImageMap;

ResourceLoadUtils::~ResourceLoadUtils() {
    m_LoadImageMap.clear();
}


void ResourceLoadUtils::init() {
    if (!instance) {
        instance.reset(new ResourceLoadUtils());
    }
}

ResourceLoadUtils &ResourceLoadUtils::getInstance() {
    // 保证init函数只被调用一次，其中m_InitFlag就是标记
    std::call_once(m_InitFlag, &ResourceLoadUtils::init);
    return *instance;
}

ImageParam ResourceLoadUtils::loadImage(const char *imagePath) {
    stbi_set_flip_vertically_on_load(true);
    if (m_LoadImageMap.find(imagePath) != m_LoadImageMap.end()) {
        return m_LoadImageMap[imagePath];
    }

    int width, height, channel;
    stbi_uc* data = stbi_load(imagePath, &width, &height, &channel, STBI_rgb_alpha);

    if (data == nullptr) {
        const std::string errorMessage = "Failed to load image: " + std::string(imagePath);
        stbi_image_free(data);  // 释放可能已部分分配的内存
        throw std::runtime_error(errorMessage);
    }
    ImageParam param(width, height, channel, data);
    m_LoadImageMap[imagePath] = param;
    return param;
}


ImageParam ResourceLoadUtils::loadImage(const char *imagePath, const bool flip) {
    stbi_set_flip_vertically_on_load(flip);
    if (m_LoadImageMap.find(imagePath) != m_LoadImageMap.end()) {
        return m_LoadImageMap[imagePath];
    }

    int width, height, channel;
    stbi_uc* data = stbi_load(imagePath, &width, &height, &channel, STBI_rgb_alpha);

    if (data == nullptr) {
        const std::string errorMessage = "Failed to load image: " + std::string(imagePath);
        stbi_image_free(data);  // 释放可能已部分分配的内存
        throw std::runtime_error(errorMessage);
    }
    ImageParam param(width, height, channel, data);
    m_LoadImageMap[imagePath] = param;
    return param;
}

ImageParam ResourceLoadUtils::loadImage(const char *imagePath, const bool flip, int req_comp) {
    stbi_set_flip_vertically_on_load(flip);
    if (m_LoadImageMap.find(imagePath) != m_LoadImageMap.end()) {
        return m_LoadImageMap[imagePath];
    }

    int width, height, channel;
    stbi_uc* data = stbi_load(imagePath, &width, &height, &channel, req_comp);

    if (data == nullptr) {
        const std::string errorMessage = "Failed to load image: " + std::string(imagePath);
        stbi_image_free(data);  // 释放可能已部分分配的内存
        throw std::runtime_error(errorMessage);
    }
    ImageParam param(width, height, channel, data);
    m_LoadImageMap[imagePath] = param;
    return param;
}

ImageParam ResourceLoadUtils::loadImage(const std::string &imagePath) {
    return loadImage(imagePath.c_str());
}

ImageParam ResourceLoadUtils::loadImage(const std::string &imagePath, const bool flip) {
    return loadImage(imagePath.c_str(), flip);
}

ImageParam ResourceLoadUtils::loadImage(const std::string &imagePath, const bool flip, int req_comp) {
    return loadImage(imagePath.c_str(), flip, req_comp);
}


void ResourceLoadUtils::clearImageCache() {
    m_LoadImageMap.clear();
}




